<template>
  <div class="scroll-list-wrap">
    <ul
      class="scroll-list"
      ref="scrollList"
      @scroll="handleScroll"
      @touchstart="handleStart"
      @touchend="handleEnd">
      <li></li>
      <li></li>
      <li v-for="(item,index) in dataList" @click.stop="handleSelect(item,index)">{{ showText(item) }}{{ suffix }}</li>
      <li></li>
      <li></li>
    </ul>
  </div>
</template>

<script>
import {Validate} from 'js-utils/validate';

export default {
  name: 'f-scroll-list',
  props: {
    dataList: {
      type: [Array, Number],
      default: () => ([])
    },
    suffix: {
      type: String,
      default: ''
    },
    value: {
      type: [Number, String, Object]
    },
    formatNum: {
      type: Boolean,
      default: true
    },
    defaultProps: {
      type: Object,
      default: () => {
        return {value: 'value', text: 'text'};
      }
    }
  },
  data() {
    return {
      itemHeight: 40,
      itemNum: 5,
      stepHeight: 5,
      manualFlag: false,
      index: 0,
      timer1: null,
      timer2: null
    };
  },
  methods: {
    formatNumber(val) {
      if (!this.formatNum) return val;
      let isNumber = !isNaN(val);
      if (isNumber) {
        val += '';
        return val[1] ? val : '0' + val;
      } else {
        return val;
      }
    },
    showText(item) {
      if (Validate.isPlainObject(item)) {
        return this.formatNumber(item[this.defaultProps.text]);
      } else {
        return this.formatNumber(item);
      }
    },
    handleStart(e) {
      this.manualFlag = true;
      clearTimeout(this.timer1);
    },
    handleMove(e) {
      // this.clearMoveBack();
    },
    handleEnd(e) {
      this.manualFlag = false;
      this.debounceScroll();
    },
    moveBack() {
      cancelAnimationFrame(this.timer2);
      let scrollList = this.$refs.scrollList;
      let scrollTop = scrollList.scrollTop;
      let height = scrollTop % this.itemHeight | 0;
      if (!height) {
        this.manualFlag = false;
        return this.submitResult();
      }
      if (height > (this.itemHeight >> 1)) {
        scrollList.scrollTop = scrollTop + 1;
      } else {
        scrollList.scrollTop = scrollTop - 1;
      }
      this.timer2 = requestAnimationFrame(this.moveBack);
    },
    moveTo(index) {
      cancelAnimationFrame(this.timer2);
      let scrollList = this.$refs.scrollList;
      let scrollTop = scrollList.scrollTop | 0;
      let targetHeight = this.itemHeight * index;
      let surplusHeight = Math.abs(targetHeight - scrollTop);
      let height = this.stepHeight < surplusHeight ? this.stepHeight : surplusHeight;
      if (scrollTop < targetHeight) {
        scrollList.scrollTop = scrollTop + height;
      } else if (scrollTop > targetHeight) {
        scrollList.scrollTop = scrollTop - height;
      } else {
        return;
      }
      this.timer2 = requestAnimationFrame(() => this.moveTo(index));
    },
    handleScroll(e) {
      if (this.manualFlag) return;
      this.debounceScroll(e);
    },
    debounceScroll() {
      clearTimeout(this.timer1);
      this.timer1 = setTimeout(() => {
        this.manualFlag = true;
        this.moveBack();
      }, 50);
    },
    handleSelect(item, index) {
      this.moveTo(index);
    },
    submitResult() {
      let scrollList = this.$refs.scrollList;
      let scrollTop = scrollList.scrollTop;
      let index = scrollTop / this.itemHeight | 0;
      let value = this.dataList[index];
      this.index = index;
      this.$emit('input', value);
      this.$emit('change', {value, index});
    },
    setScrollTop() {
      let index = this.dataList.indexOf(this.value);
      this.$nextTick(() => {
        if (index > -1) {
          this.$refs.scrollList.scrollTop = index * this.itemHeight;
        } else {
          this.submitResult();
        }
      });
    }
  },
  watch: {
    value: 'setScrollTop',
    dataList: 'setScrollTop'
  },
  mounted() {
    this.setScrollTop();
  }
};
</script>

<style scoped>
.scroll-list-wrap {
  flex: 1;
  height: 200px;
  overflow: hidden;
}

.scroll-list {
  width: calc(100% + 20px);
  height: 100%;
  overflow: auto;
  padding-right: 15px;
  -webkit-overflow-scrolling: touch;
  will-change: scroll-position;
}

.scroll-list li {
  width: 100%;
  height: 40px;
  line-height: 40px;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0 5px;
  user-select: none;
}
</style>
